/*
  AdViEmulator - AdventureVision emulator
  Copyright (C) 2012-2013  JustBurn

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "soundout.h"

SoundOut::SoundOut()
	: audDevice(QAudioDeviceInfo::defaultOutputDevice())
{
	enabled = false;
	WBuffer = 0;
	WBufferSize = 0;
	buffSize = 8192;

	// Setup audio
	audFormat.setSampleRate(44100);
	audFormat.setChannelCount(1);
	audFormat.setSampleSize(8);
	audFormat.setCodec("audio/pcm");
	audFormat.setByteOrder(QAudioFormat::LittleEndian);
	audFormat.setSampleType(QAudioFormat::UnSignedInt);
	QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
	if (!info.isFormatSupported(audFormat)) {
		qWarning("Default format not supported - trying to use nearest\n");
		audFormat = info.nearestFormat(audFormat);
	}
	audOutput = new QAudioOutput(audDevice, audFormat);
	if (audOutput) audOutput->setBufferSize(buffSize);
}

SoundOut::~SoundOut()
{
	TerminateQ();
}

bool SoundOut::InitializeQ(void)
{
	if (!audOutput || !audOutput) return false;
	enabled = false;

	audOutput->setBufferSize(buffSize);
	audIODev = audOutput->start();
	if (!audIODev) return false;

	WBuffer = new quint8[audOutput->periodSize() + 1024];
	WBufferSize = audOutput->periodSize();
	memset(WBuffer, 0x80, WBufferSize);

	enabled = true;
	return true;
}

void SoundOut::TerminateQ(void)
{
	if (!enabled) return;

	audOutput->stop();
	delete[] WBuffer;
	WBuffer = 0;
	WBufferSize = 0;

	enabled = false;
}

int SoundOut::GetBuffersFree(void)
{
	if (!enabled) return 0;

	int val = audOutput->bytesFree() / audOutput->periodSize();
	return qMin(val, 1);
}

void SoundOut::BufferSend(void)
{
	if (!enabled) return;

	audIODev->write((char *)WBuffer, WBufferSize);
}

void SoundOut::Enable(bool enable)
{
	if (enable) {
		if (enabled) return;
		InitializeQ();
	} else {
		if (!enabled) return;
		TerminateQ();
	}
}

void SoundOut::Play(bool enable)
{
	Q_UNUSED(enable);
}

void SoundOut::SetBufferSize(int numsamples)
{
	if (numsamples < 1024) numsamples = 1024;
	if (numsamples > 32768) numsamples = 32768;
	numsamples--;
	numsamples |= numsamples >> 8;
	numsamples |= numsamples >> 4;
	numsamples |= numsamples >> 2;
	numsamples |= numsamples >> 1;
	numsamples++;
	if (numsamples == buffSize) return;

	// Restart entire sound
	TerminateQ();
	buffSize = numsamples;
	InitializeQ();
}

int SoundOut::GetBufferSize()
{
	return buffSize;
}
